import { isString } from 'lodash-es';
import { atob } from './pollify';
import { t } from '@services/i18n.service';
import { useApi } from './api';

/**
 * From Wise Team
 * @param data
 */
export const downloadBlob = (data: any) => {
  const contentDisposition = data.headers['content-disposition'];
  const index = contentDisposition.indexOf('e=');
  const fileName =
    contentDisposition.slice(index + 3, contentDisposition.length - 1) ||
    new Date().getTime() + '.csv';
  download(fileName, data.data);
};

/**
 *
 * From Wise Team
 * @param fileName
 * @param blob
 */
export const download = (fileName: string, blob: Blob) => {
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = fileName;
  link.click();
  link.remove();
  URL.revokeObjectURL(link.href);
};

/**
 * From Wise Team
 * 文件下载函数
 */
export function fileDownload(file: string | Blob, name: string) {
  if (!file) {
    throw new Error(t('common.File_should_not_be_empty'));
  }

  // file是url
  if (isString(file) && file.indexOf('http') > -1) {
    name = name || getUrlFileName(file);
    const link = document.createElement('a');
    link.style.display = 'none';
    link.href = file;
    link.target = '_blank';
    link.setAttribute('download', name); // 自定义下载文件名（如exemple.txt）
    document.body.appendChild(link);
    link.click();
    return;
  }

  if (!name) {
    throw new Error(t('File_name_should_not_be_empty'));
  }

  // file是base64先转blob
  let blobFile;
  if (isString(file)) {
    blobFile = base64toBlob(file);
  }

  if (!blobFile) return;

  // file是blob
  if ((window.navigator as any).msSaveBlob) {
    (window.navigator as any).msSaveOrOpenBlob(blobFile, name);
  } else {
    const url = window.URL.createObjectURL(new Blob([blobFile]));
    const link = document.createElement('a');
    link.style.display = 'none';
    link.href = url;
    link.target = '_blank';
    link.setAttribute('download', name); // 自定义下载文件名（如exemple.txt）
    document.body.appendChild(link);
    link.click();
  }
}

/**
 * From Wise Team
 * 获链接文件名+后缀
 * @param {string} url 文件地址
 */
export function getUrlFileName(url: string) {
  if (!url) return '';
  const file = url.split('/');
  return file[file.length - 1] || '';
}

/**
 * From Wise Team
 * 从base64编码的图片中获取扩展名
 * @param {String} base64
 * @returns {String}
 */
export function getExtensionFromBase64(base64: string) {
  const re = new RegExp('/(?<ext>.*?);base64,.*');
  const res = re.exec(base64);
  if (res) {
    return res.groups?.ext;
  }
}

/**
 * From Wise Team
 * 判断是否为base64格式文件
 * @param {String} base64
 * @returns {Boolean}
 */
export function checkBase64(base64: string) {
  const re = new RegExp('/(?<ext>.*?);base64,.*');
  return re.exec(base64);
}

/**
 * From Wise Team
 * 获取uuid
 * @returns {String}
 */
export function getUUID() {
  const s = [];
  const hexDigits = '0123456789abcdef';
  for (let i = 0; i < 36; i++) {
    s[i] = hexDigits.substring(Math.floor(Math.random() * 0x10), 1);
  }
  s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
  s[19] = hexDigits.substring(((s as any)[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
  s[8] = s[13] = s[18] = s[23] = '-';
  const uuid = s.join('');
  return uuid;
}

/**
 * From Wise Team
 * Base64 转 Blob
 * @param {string} base64String Blob格式数据
 */
export function base64toBlob(base64String: string) {
  const arr = base64String.split(',');
  if (arr.length < 2) return;

  const mime = arr[0].match(/:(.*?);/)?.[1];
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], {
    type: mime,
  });
}

/**
 * From Wise Team
 * Blob 转 Base64
 * @param {blob} file Blob格式数据
 */
export function blobToBase64(file: Blob) {
  return new Promise(function (resolve, reject) {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function () {
      resolve(reader.result);
    };
    reader.onerror = function (error) {
      reject(error);
    };
  });
}

/**
 * From Wise Team
 * 压缩base64图片
 * @param {string} base64String base64格式数据
 * @param {number} w 宽度
 * @param {number} quality 文件质量（0~1）
 */
export function compressImg(base64String: string, w: number, quality: number) {
  const getMimeType = function (urlData: string) {
    const arr = urlData.split(',');
    const mime = arr[0].match(/:(.*?);/)?.[1];
    return mime;
  };
  const newImage = new Image();
  let imgWidth, imgHeight;

  const promise = new Promise(function (resolve) {
    newImage.onload = resolve;
  });
  newImage.src = base64String;
  return promise.then(function () {
    imgWidth = newImage.width;
    imgHeight = newImage.height;
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    if (Math.max(imgWidth, imgHeight) > w) {
      if (imgWidth > imgHeight) {
        canvas.width = w;
        canvas.height = (w * imgHeight) / imgWidth;
      } else {
        canvas.height = w;
        canvas.width = (w * imgWidth) / imgHeight;
      }
    } else {
      canvas.width = imgWidth;
      canvas.height = imgHeight;
    }
    ctx?.clearRect(0, 0, canvas.width, canvas.height);
    ctx?.drawImage(newImage, 0, 0, canvas.width, canvas.height);
    const base64 = canvas.toDataURL(getMimeType(base64String), quality);
    return base64;
  });
}

/**
 * From Wise Team
 * 获取base64文件大小，返回KB数字
 * @param {string} base64String base64格式数据
 */
export function getBase64Size(base64String: string) {
  let str = base64String.split(',')[1];
  const equalIndex = str.indexOf('=');
  if (str.indexOf('=') > 0) {
    str = str.substring(0, equalIndex);
  }
  const strLength = str.length;
  const fileLength = parseInt(`${strLength - (strLength / 8) * 2}`);
  // 由字节转换为KB
  let size = '';
  size = (fileLength / 1024).toFixed(2);
  const sizeStr = size + ''; // 转成字符串
  const index = sizeStr.indexOf('.'); // 获取小数点处的索引
  const dou = sizeStr.substring(index + 1, 2); // 获取小数点后两位的值
  if (dou == '00') {
    // 判断后两位是否为00，如果是则删除00
    return sizeStr.substring(0, index) + sizeStr.substring(index + 3, 2);
  }
  return parseInt(size);
}

export function getFileName(url: string): string {
  return url.substring(url.lastIndexOf('/') + 1);
}

function isFileSizeLessThan(f: File, mib: number = 2): boolean {
  return f.size / 1024 / 1024 < mib;
}

export function isDataURL(str: string): boolean {
  return /^data:(\S+)(;base64){0,1},.*$/gi.test(str);
}

/**
 *
 * @param param
 * @example
 * const { data } = await wget({ url: 'http://localhost:8080/favicon.png', type: 'image/*' });
 */
async function wget({
  url,
  type,
}: {
  /* File Url */ url: string;
  /* MIME type */ type: string;
}): Promise<Blob> {
  const api = useApi();
  const response = await api.get<Blob>(
    url,
    {},
    {
      headers: {
        accept: type || 'image/*',
        'content-Type': 'application/json',
      },
      responseType: 'blob',
    }
  );
  console.log('wget response', response, response.data);
  return response.data;
}

export async function readAsDataURL(url: string): Promise<string> {
  const blob = await wget({ type: 'image/*', url });
  const read_as_data_url = new Promise<string>((resolve) => {
    const reader = new FileReader();
    reader.addEventListener(
      'load',
      () => {
        const result = reader.result;

        console.log('readAsDataURL load result ', result);

        if (isString(result)) {
          resolve(result);
        } else {
          resolve('');
        }
      },
      false
    );
    reader.readAsDataURL(blob);
  });
  const base64 = await read_as_data_url;
  return base64;
}

export async function readAsFile(base64: string, name: string, type: string): Promise<File> {
  const arr = base64.split(',');
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  const blob = new Blob([u8arr], {
    type,
  });
  return new File([blob], name);
}

/**
 * ajax upload file
 * @param fs
 * @param options
 * @returns
 */
export function upload(
  fs: File[],
  options: {
    action: string;
  } & Partial<{
    timeout: number;
    onAbort: (event: ProgressEvent<EventTarget>) => void;
    onError: (event: ProgressEvent<EventTarget>) => void;
    onLoad: (event: ProgressEvent<EventTarget>) => void;
    onProgress: (event: ProgressEvent<EventTarget>) => void;
    onTimeout: (event: ProgressEvent<EventTarget>) => void;
  }>
): XMLHttpRequest {
  const {
    action,
    timeout = 0,
    onAbort = () => {},
    onError = () => {},
    onLoad = () => {},
    onProgress = () => {},
    onTimeout = () => {},
  } = options;

  const xhr = new XMLHttpRequest();
  xhr.timeout = timeout;
  xhr.open('POST', action);

  xhr.upload.onabort = function (event) {
    onAbort(event);
  };
  xhr.upload.onerror = function (event) {
    onError(event);
  };
  xhr.onload = function (event: any) {
    onLoad(event);
  };
  xhr.upload.onprogress = function (event) {
    onProgress(event);
  };
  xhr.upload.ontimeout = function (event) {
    onTimeout(event);
  };

  xhr.send(
    (() => {
      /**
       * @see [Uploading multiple files using formData()](https://stackoverflow.com/questions/12989442/uploading-multiple-files-using-formdata)
       */
      const fd = new FormData();
      fs.forEach((f) => {
        fd.append('files[]', f);
      });
      return fd;
    })()
  );

  return xhr;
}

export interface IUploadedFile {
  name: string;
  size: number;
  type: string;
  orientation: string;
  url: string;
  deleteUrl: string;
  deleteType: string;
  file_id: string;
  file_key: string;
  barcode: number;
  data: any[];
  watermark_pass: number;
}
export const FILE_UPLOAD_ENDPOINT = 'https://files2.fr8taxi.com/uploader/';
export async function uploadSignature(file: File): Promise<IUploadedFile> {
  const do_upload = new Promise<IUploadedFile>((resolve, reject) => {
    function fail(event: any): void {
      reject(event);
    }

    upload([file], {
      action: FILE_UPLOAD_ENDPOINT,
      onAbort: fail,
      onError: fail,
      onLoad: (event) => {
        const target = event.target as XMLHttpRequest | null;
        if (!target) {
          return;
        }

        if (target.status === 200 && target.readyState === 4) {
          try {
            const response = target.response;
            const result = isString(response) ? JSON.parse(response) : response;

            resolve(result.files[0]);
          } catch (error) {
            console.error(error);
            fail(event);
          }
        } else {
          fail(event);
        }
      },
      onProgress: () => {},
      onTimeout: fail,
    });
  });

  return await do_upload;
}

function formatFileSize(bytes: number, si = false, dp = 1): string {
  const thresh = si ? 1000 : 1024;

  if (Math.abs(bytes) < thresh) {
    return bytes + ' B';
  }

  const units = si
    ? ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
  let u = -1;
  const r = 10 ** dp;

  do {
    bytes /= thresh;
    ++u;
  } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);

  return bytes.toFixed(dp) + ' ' + units[u];
}

export { formatFileSize, isFileSizeLessThan };
